home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Memory / Cache Flushing / Cache.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  6.2 KB  |  163 lines  |  [TEXT/MPS ]

  1. /*
  2.  *    File:        Cache.c
  3.  *
  4.  *    Contains:    FlushCacheRange: a machine and system independent cache flush routine
  5.  *
  6.  *    Cache control is a highly CPU specific function.  Although some system independence
  7.  *    is achieved via use of the _HWPriv trap, this solution may not be general for all
  8.  *    hardware/system software combinations.  FlushCacheRange should solve that for
  9.  *    developers by working on all systems.
  10.  *    
  11.  *    Written by:    Dave Radcliffe
  12.  *
  13.  *    Copyright:    © 1991 by Apple Computer, Inc., all rights reserved.
  14.  *
  15.  *    Change History:
  16.  *
  17.  *        1/20/92        DR        Added System603OrLater conditional code
  18.  *        1/10/92        DR        Added FlushCacheWithCPushA()
  19.  *        12/18/91    DR        New today
  20.  *
  21.  */
  22.  
  23. #ifndef __TYPES__
  24. #include <Types.h>
  25. #endif
  26.  
  27. #ifndef __TRAPS__
  28. #include <Traps.h>
  29. #endif
  30.  
  31. #ifndef __OSUTILS__
  32. #include <OSUtils.h>
  33. #endif
  34.  
  35. #ifndef __GESTALTEQU__
  36. #include <GestaltEqu.h>
  37. #endif
  38.  
  39. #ifndef __ERRORS__
  40. #include <Errors.h>
  41. #endif
  42.  
  43. /*
  44.  * If you can guarantee you are running on System 6.0.3 or later, then some of the
  45.  * alternative cache flushing code implemented below is unnecessary as you are
  46.  * assured of having the _HWPriv trap.  So, if you are running on System 6.0.3 or
  47.  * later, uncommenting the following line can reduce this code by more than half.
  48.  */
  49. /* #define System603OrLater */
  50.  
  51. /* The next two declarations are defined in Tech Note #261 */
  52. #ifndef FlushCodeCacheRange
  53. /* MPW C 3.1 and earlier, and THINK C should declare the function as   */
  54. /* “pascal” and use the same inline constants as the Pascal interface: */
  55. pascal OSErr FlushCodeCacheRange (void *address, unsigned long count) =
  56.     {0x225F, 0x205F, 0x7009, 0xA198, 0x3E80};
  57.     
  58. /* The above declaration works for MPW C 3.2 as well, but 3.2 allows   */
  59. /* register specifications to make register-based inline calls very    */
  60. /* efficient.  So, under MPW C 3.2, you may choose to uncomment the    */
  61. /* following code, instead.                                            */
  62. /*
  63. #pragma parameter __D0 FlushCodeCacheRange(__A0,__A1)
  64. OSErr FlushCodeCacheRange (void *address, unsigned long count) =
  65.     {0x7009, 0xA198};
  66.  */
  67. #endif
  68.  
  69. #ifndef FlushCodeCache
  70. #define _CacheFlush 0xA0BD
  71. void FlushCodeCache (void) = _CacheFlush;
  72. #endif
  73.  
  74. /* 
  75.  * FlushCacheViaCACR is an inline assembly routine that flushes both the 
  76.  * instruction and data caches by writing directly to the CACR.  Used only
  77.  * as a last resort by FlushCacheRange
  78.  */
  79. void FlushCacheViaCACR ( void ) =
  80.     { 0x4E7A, 0x0002,        /* MOVEC    CACR,D0 */
  81.       0x08C0, 0x0003,        /* BSET        #3,D0   */
  82.       0x4E7B, 0x0002 };        /* MOVEC    D0,CACR */
  83.  
  84. /*
  85.  * FlushCacheWithCPushA is another inline assembly routine that flushes caches
  86.  * on the MC68040 using the CPushA instruction.  Used only as a last resort
  87.  * by FlushCacheRange
  88.  */
  89. void FlushCacheWithCPushA ( void ) =
  90.     { 0x4E71,                /* NOP, to clear pending writes */
  91.       0xF4F8 };                /* CPUSHA    BC */
  92.       
  93. /*
  94.  * FlushCacheRange flushes both the data and instruction caches for the block of 
  95.  * memory starting at location address with size count.  Flushing the cache for 
  96.  * a range of memory is only supported on the 68040, so if this functionality is
  97.  * unavailable, the entire cache is flushed (if appropriate).
  98.  *
  99.  * If either address is NIL or count is zero, the entire cache is flushed anyway.
  100.  * Selective flushing of the cache is a time consuming process and you may wish to
  101.  * avoid it when there is no benefit to doing so.  For example, if you've recently
  102.  * manipulated a block larger than 4K (the size of the 68040 caches), selective
  103.  * flushing will probably end up flushing the entire cache anyway, so why bother?
  104.  *
  105.  * The preferred method for flushing the cache is to use the _HWPriv trap documented
  106.  * in Tech Note #261.  Some older systems may not have this trap implemented, so
  107.  * alternate methods must be used.  The first thing to try is the _CacheFlush trap.
  108.  * This was implemented beginning with the Mac II (and is also documented in Tech
  109.  * Note #261).
  110.  *
  111.  * MC68000 based systems have no cache, but if an accelerator board has been added.
  112.  * they may have a CPU which does have a cache.  Accelerator board vendors should
  113.  * implement _HWPriv or _CacheFlush for such systems, but if they haven't then
  114.  * our last resort is to control the caches directly (using privileged
  115.  * instructions (GAK!!)).
  116.  *
  117.  * FINALLY, the full implementation of FlushCacheRange is probably overkill and may be 
  118.  * less than optimal for some applications.  For example, testing for _HWPriv 
  119.  * should be unnecessary on systems later than 6.0.2, so I've added conditional code
  120.  * to allow you to bypass that if appropriate (see comment above on System603OrLater).
  121.  * The full implementation tries to cover a lot of obscure cases, but it also does 
  122.  * some things inefficiently.  For example, having determined the _HWPriv is 
  123.  * implemented, it would be more efficient to just keep that information around, 
  124.  * but I wanted to avoid the complications of global or static variables.  But 
  125.  * it is also true that if you find it necessary to call this code more than a
  126.  * few times between the time your application starts and the time it quits, 
  127.  * YOU ARE DOING SOMETHING WRONG!!   Go back and rethink your code.
  128.  */
  129. void FlushCacheRange (void *address, unsigned long count)
  130. {
  131. #ifndef System603OrLater
  132.     long    gestaltResponse;            /* For CPU type */
  133.     long    unimpTrapAddress;            /* Address of Unimplemented Trap */
  134.     
  135.     /* First check to see if _HWPriv is implemented */
  136.     if ((unimpTrapAddress = NGetTrapAddress(_Unimplemented, ToolTrap)) != 
  137.         NGetTrapAddress(_HWPriv, OSTrap)) {
  138. #endif
  139.         /* 
  140.          * Try to flush the specified range.  If it fails or if there is no range,
  141.          * then flush the entire cache 
  142.          */
  143.         if (!(address && count && (FlushCodeCacheRange (address, count) != hwParamErr))) {    
  144.             /* Flush entire cache */
  145.             FlushInstructionCache ();
  146.         }
  147. #ifndef System603OrLater
  148.     } else {                /* No _HWPriv trap */
  149.         /* Try for _CacheFlush trap */
  150.         if (unimpTrapAddress != NGetTrapAddress(_CacheFlush, OSTrap))
  151.             FlushCodeCache ();
  152.         else        /* Nothing else works, so do machine specific cache control */
  153.             /* Only bother with cache control on 68020 and above */
  154.             if (!Gestalt (gestaltProcessorType, &gestaltResponse) && 
  155.                 (gestaltResponse >= gestalt68020))
  156.                     if (gestaltResponse <= gestalt68030)
  157.                         FlushCacheViaCACR ();
  158.                     else
  159.                         FlushCacheWithCPushA ();
  160.     }
  161. #endif
  162.     return;
  163. }    /* FlushCacheRange */